//
//  JDURLSession.swift
//  funcode
//
//  Created by Wan Jiading on 2017/2/7.
//  Copyright © 2017年 WanJiading. All rights reserved.
//  这个connenction的功能是把task缓存到本地的临时数据根据播放器需要的 offset和length去取数据并返回给播放器

import UIKit
import AVFoundation
import MobileCoreServices

@objc protocol JDResourceLoaderDelegate: NSObjectProtocol {
	@objc optional func didFinishLoading(_ loader: JDResourceLoader, _ task: JDVideoRequestTask)
	@objc optional func didFailLoading(_ loader: JDResourceLoader, _ task: JDVideoRequestTask, _ errorCode: Int)
}

class JDResourceLoader: NSObject, JDVideoRequestTaskDelegate, AVAssetResourceLoaderDelegate {
	
	var task: JDVideoRequestTask?
	var delegate: JDResourceLoaderDelegate!
	
	private var pendingRequests: [AVAssetResourceLoadingRequest]!
	private var videoPath: String!
	
	override init() {
		super.init()
		
		pendingRequests = [AVAssetResourceLoadingRequest]()
		
		self.videoPath = JDPlayerUtil.tempVideoFilePath()
		
	}
	
	func fillInContentInfomation(_ contentInformationRequest: AVAssetResourceLoadingContentInformationRequest?) {
		if contentInformationRequest == nil {
			return
		}
		
		JDPlayerUtil.fill(inContentInformation: contentInformationRequest, mimeType: self.task!.mimeType, videoLength: self.task!.videoLength)
	}
	
	// MARK: - AVURLAsset resource loader methods
	
	private func processPendingRequests() {
		var requestsCompleted = [AVAssetResourceLoadingRequest]() // 请求完成的数组
		
		// 每次下载一块数据都是一次请求，把这些请求放到数组，遍历数组
		for loadingRequest in self.pendingRequests {
			self.fillInContentInfomation(loadingRequest.contentInformationRequest) // 对每次请求加上长度，文件类型等信息
			
			let didRespondCompletely = self.respond(loadingRequest.dataRequest!)	// 判断此次请求的数据是否处理完全
			if didRespondCompletely {
				requestsCompleted.append(loadingRequest) // 如果完整，把此次请求放进 请求完成的数组
				loadingRequest.finishLoading()
			}
		}
		
		//在所有请求的数组中移除已经完成的
		for request in requestsCompleted {
			if let index = self.pendingRequests.index(of: request) {
				self.pendingRequests.remove(at: index)
			}
		}
	}
	
	private func respond(_ dataRequest: AVAssetResourceLoadingDataRequest) -> Bool {
		var startOffset = UInt(dataRequest.requestedOffset)
		if dataRequest.currentOffset != 0 {
			startOffset = UInt(dataRequest.currentOffset)
		}
		
		if self.task!.offset + self.task!.downloadingOffset < startOffset {
			return false
		}
		
		if startOffset < self.task!.offset {
			return false
		}
		
		do {
			let fileData = try NSData(contentsOf: URL(fileURLWithPath: self.videoPath), options: .mappedIfSafe)
			
			let unReadBytes = self.task!.downloadingOffset - (startOffset - self.task!.offset)
			
			let numberOfBytesToRespondWith = min(dataRequest.requestedLength, Int(unReadBytes))
			
			let data = fileData.subdata(with: NSRange(location: Int(startOffset - self.task!.offset), length: numberOfBytesToRespondWith))
			
			dataRequest.respond(with: data)
			
			let endOffset = startOffset + UInt(dataRequest.requestedLength)
			
			let didRespondFully = (self.task!.offset + self.task!.downloadingOffset) >= endOffset
			
			return didRespondFully
		} catch {
			ExceptionLog("【try 失败】 try NSData(contentsOf: URL(fileURLWithPath: self.videoPath), options: .mappedIfSafe) videoPath = \(videoPath)")
			return false
		}
	}
	
	
	/// 必须返回Yes，如果返回NO，则resourceLoader将会加载出现故障的数据
	/// 这里会出现很多个loadingRequest请求， 需要为每一次请求作出处理
	///
	/// - Parameters:
	///   - resourceLoader: 资源管理器
	///   - loadingRequest: 每一小块数据的请求
	func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool {
		
		self.pendingRequests.append(loadingRequest)
		self.dealLoadingRequest(loadingRequest)
		
		return true
	}
	
	private func dealLoadingRequest(_ loadingRequest: AVAssetResourceLoadingRequest) {
		let interceptedURL = loadingRequest.request.url
		if interceptedURL == nil {
			ExceptionLog("异常  loadingRequest.request.url == nil")
			return
		}
		if loadingRequest.dataRequest == nil {
			ExceptionLog("异常  loadingRequest.dataRequest == nil")
			return
		}
		let range = NSRange(location: Int(loadingRequest.dataRequest!.currentOffset), length: Int.max)
		if self.task != nil && self.task!.downloadingOffset > 0 {
			self.processPendingRequests()
		}
		
		if self.task == nil {
			self.task = JDVideoRequestTask()
			self.task!.delegate = self
			self.task!.setUrl(interceptedURL!, 0)
		} else {
			// 如果新的rang的起始位置比当前缓存的位置还大300k，则重新按照range请求数据
			if self.task!.offset + (self.task!.downloadingOffset) + UInt(1024 * 300) < UInt(range.location) ||
				// 如果往回拖也重新请求
				UInt(range.location) < self.task!.offset {
				self.task?.setUrl(interceptedURL!, UInt(range.location))
			}
		}
	}
	
	func resourceLoader(_ resourceLoader: AVAssetResourceLoader, didCancel loadingRequest: AVAssetResourceLoadingRequest) {
		if let index = self.pendingRequests.index(of: loadingRequest) {
			self.pendingRequests.remove(at: index)
		}
	}
	
	func getSchemeVideoURL(_ url: URL) -> URL? {
		if let components = NSURLComponents(url: url, resolvingAgainstBaseURL: false) {
			components.scheme = "streaming"
			return components.url!
		}
		return nil
	}
	
	// MARK: - JDVideoRequestTaskDelegate
	
	func didReceiveVideoData(_ task: JDVideoRequestTask) {
		self.processPendingRequests()
	}
	
	func didFinishLoading(_ task: JDVideoRequestTask) {
		DebugLog("加载完成")
		if self.delegate.responds(to: #selector(JDResourceLoaderDelegate.didFinishLoading(_:_:))) {
			self.delegate.didFinishLoading!(self, task)
		}
	}
	
//	func task(_ task: JDVideoRequestTask, _ didReceiveVideoLength: UInt, _ mimeType: String) {
//		DebugLog("接收到参数")
//	}
	
	func didFailLoading(_ task: JDVideoRequestTask, _ errorCode: UInt) {
		// TODO 下面一行有问题
		if self.delegate.responds(to: #selector(JDResourceLoaderDelegate.didFailLoading(_:_:_:))) {
			self.delegate.didFailLoading!(self, task, Int(errorCode))
		}
	}
}
